#include "GeometryUtils.h"

#include "Wm5IntrLine3Box3.h"
#include "Wm5IntrLine3Triangle3.h"
#include "Wm5IntrBox3Box3.h"
#include "Wm5IntrTriangle3Triangle3.h"
#include "Wm5IntrTriangle2Triangle2.h"
#include "Wm5IntrTriangle3Box3.h"
#include "Wm5IntrRay3Triangle3.h"
#include "Wm5IntrRay2Box2.h"

bool IntersectionTest(const TLine3& i_line, const TBox3& i_box)
  {
  // use WildMagic test from LibMathematics
  Wm5::IntrLine3Box3<double> tester(i_line, i_box);
  return tester.Test();
  }

bool IntersectionTest(const TLine3& i_line, const TTriangle3& i_triangle)
  {
  // use WildMagic test from LibMathematics
  Wm5::IntrLine3Triangle3<double> tester(i_line, i_triangle);
  return tester.Test();
  }

bool IntersectionTest(const TBox3& i_box_1, const TBox3& i_box_2)
  {
  // use WildMagic test from LibMathematics
  Wm5::IntrBox3Box3<double> tester(i_box_1, i_box_2); 
  return tester.Test();
  }

bool IntersectionTest(const TTriangle3& i_triangle_1, const TTriangle3& i_triangle_2)
  {
  // use WildMagic test from LibMathematics
  Wm5::IntrTriangle3Triangle3<double> tester(i_triangle_1, i_triangle_2);
  return tester.Test();
  }

bool AreaIntersectionTest(const TTriangle2& i_triangle1, const TTriangle2& i_triangle2)
  {
  // use WildMagic test from LibMathematics
  Wm5::IntrTriangle2Triangle2<double> tester(i_triangle1, i_triangle2);
  tester.Find();
  auto how_intersect = tester.GetQuantity();
  // defining the type of the intersection
  if(how_intersect == tester.IT_EMPTY || how_intersect == tester.IT_POINT || how_intersect == tester.IT_SEGMENT)
     return false;
  else
    return true;
  }

bool IntersectionTest(const TTriangle3& i_triangle, const TBox3& i_box)
	{
	// use WildMagic test from LibMathematics
	Wm5::IntrTriangle3Box3<double> tester(i_triangle, i_box);
	return tester.Test();
	}

bool IntersectionTest(const TTriangle3& i_triangle, const TRay3& i_ray)
	{
	// use WildMagic test from LibMathematics
	Wm5::IntrRay3Triangle3<double> tester(i_ray, i_triangle);
	return tester.Test();
	}

bool GetIntersectionPoint(TVector3& o_result, const TTriangle3& i_triangle, const TRay3& i_ray)
  {
  Wm5::IntrRay3Triangle3<double> tester(i_ray, i_triangle);
  if (tester.Find())
    {
    auto t = tester.GetRayParameter();
    o_result = i_ray.Origin + t * i_ray.Direction;
    return true;
    }
  return false;
  }

double GetDistanceBetweenPoints(const TVector3& i_a, const TVector3& i_b)
  {
  return sqrt((i_a.X() - i_b.X()) * (i_a.X() - i_b.X()) +
              (i_a.Y() - i_b.Y()) * (i_a.Y() - i_b.Y()) +
              (i_a.Z() - i_b.Z()) * (i_a.Z() - i_b.Z()));
  }


bool IsInClockwiseOrder2D(const std::vector<TVector2>& i_points)
  {
  double area = 0;
  for (size_t i = 0; i < i_points.size(); ++i)
    {
    area += (i_points[(i + 1) % i_points.size()].X() - i_points[i].X()) * (i_points[(i + 1) % i_points.size()].Y() + i_points[i].Y());
    }
  return area > 0;
  }

bool GetIntersectionPoint(TVector2& o_result, const TBox2& i_box, const TRay2& i_ray)
  {
  Wm5::IntrRay2Box2<double> tester(i_ray, i_box);
  if (tester.Find())
    {
    o_result=tester.GetPoint(0);
    return true;
    }
  return false;
  }

TRay2 GetProjectionOnXY(const TLine3& i_line)
  {
  const TVector2 origin (i_line.Origin.X(), i_line.Origin.Y());
  const TVector2 direction (i_line.Direction.X(), i_line.Direction.Y());
  return TRay2 (origin,direction);
  };

TTriangle2 GetProjectionOnXY(const TTriangle3& i_triangle)
  {
  std::vector<TVector2> point_vector;
  for(size_t i = 0; i < 3; ++i)
    point_vector.push_back(TVector2(i_triangle.V[i].X(), i_triangle.V[i].Y()));
  return TTriangle2(point_vector[0], point_vector[1], point_vector[2]);
  };